/**
 * @author Ahammer
 * @date   2009 09
 * @update 2010 01 Aperio jpeg2000 33005 compression 
 * @update 2010 05 registering tiff reader if reader is not available through native imagio
 */

/*
 * For jpeg2000 compressed svs files the loci-tools package is used.
 * See Bio-Formats  http://www.loci.wisc.edu/software/bio-formats
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tools;

import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.stream.ImageInputStream;
import javax.media.jai.BorderExtender;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedImageAdapter;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import loci.formats.FormatException;
import loci.formats.gui.BufferedImageReader;
import main.Board;
import main.IqmTools;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecoder;
import com.sun.media.jai.codec.SeekableStream;
import com.sun.media.jai.codec.TIFFDecodeParam;

/** 
 * 
 * */
public class ExtractSVS {
	
	private static int extension = 0;
	
	private static  File currImgDir;
	
	/*
	 * This method sets the default directory
	 */
	private static void setDefaultDirectory(JFileChooser fc ){
		currImgDir = fc.getCurrentDirectory();
		IqmTools.setCurrImgPath(currImgDir);
	
		//Save property to iqm.ini file
		IqmTools.setIqmIniFile("CurrImgPath", currImgDir.toString());
	}
	/*
	 * This method appends String(num) to the image name
	 */
	private static File appendTextToImageName(File file, String strAppend){
	    String str  = file.toString();
	    int dotPos  = str.lastIndexOf(".");
	    String name = str.substring(0, dotPos);
	    String ext  = str.substring(dotPos+1);  //"svs"
	    if (extension == 0) ext = "tif";  
	    if (extension == 1) ext = "jpg";  
	    if (extension == 2) ext = "png";  
	    if (extension == 3) ext = "bmp";  
	    str = name+strAppend+"."+ext;  
		return new File(str);	
	}
	
	
	/*
	 * 
	 * @param file
	 * @return
	 */
    private static int[] displayImageDataAndChoose_ImgNumber_RescaleFactor_InterP(File file){
        int num     = 0; // image number
        int rescale = 1; // rescale factor
        int interP  = 1;
    	int firstWidth  = 0;
    	int firstHeight = 0;
        
		try {	          
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            
            if (!readers.hasNext()) { //no reader available, perhaps simple imageio without tiff reader installed
		    	   IIORegistry registry = IIORegistry.getDefaultInstance();  
		    	   //registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageWriterSpi());  
		    	   registry.registerServiceProvider(new com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi()); 
		    	   Board.appendTexln("ExtractSVS: additional tiff reader registered");
		    	   readers = ImageIO.getImageReaders(iis);      
	        }    
           
            if (readers.hasNext()) {//reader(s) available

                // pick the first available ImageReader
                ImageReader reader = readers.next();	    
           
                // attach source to the reader
                reader.setInput(iis, false);  // ImageInputStream,  boolean seekForwardOnly

                // read metadata of first image
                //reader.getNumThumbnails(arg0);
               
                int numImages = reader.getNumImages(true); //boolean allowSearch (allowSearch == true und seekForwardOnly == true  geht nicht) 
            	Board.appendTexln("ImageHeader: Number of Images: " +numImages);

            	//BoardJ.appendTexln("ImageHeader: File contains more than one image");
            	firstWidth  = reader.getWidth(0);
            	firstHeight = reader.getHeight(0);
            	for (int n = 0; n < numImages; n++){
            		int width  = reader.getWidth(n);
            		int height = reader.getHeight(n);
            		float ratioWidth  = (float)firstWidth  / width;
            		float ratioHeight = (float)firstHeight / height;
            		String strNumber       = String.format("%3d", n+1);
            		String strWidth        = String.format("%6d", width);
            		String strHeight       = String.format("%6d", height);
            		String strRatioWidth   = String.format("%5.1f", ratioWidth);
            		String strRatioHeight  = String.format("%5.1f", ratioHeight);
            		Board.appendTexln("Image Number:" + strNumber + "     Width:" + strWidth + "   Height:" + strHeight+ "     Width Ratio:" + strRatioWidth+":1" + "  Height Ratio:" + strRatioHeight+":1" );
            	}
                if (numImages == 1){ //standard
                	num = 0;
                }                	              
                if (numImages == -1){ //allowSearch is false and a search would be required. 
                	num = 0;
                }                	              
                if (numImages > 1){

                	//interactive applet
                	//HeaderImgNumSelection hins = new HeaderImgNumSelection();
                	//hins.createAndShowGUI();
                	ExtractSVSSelection select = new ExtractSVSSelection(numImages);
                	select.displayDialog();
                	int[] values = select.getSelectedValues(); 
                   	num     = values[0] - 1;      //selected image number
                   	rescale = values[1];      //selected rescale factor
                   	interP  = values[2];	  //selected interpolation method
                   	extension     = values[3];      //selected output image extension
                    if ((num < 0) || (rescale < 1)){ //Abbruch
                		return new int[]{0, 1, 1};
                	}
                }
           }else{
        	   Board.appendTexln("ExtractSVS Note: No image readers available (perhaps imageio is not installed)");
        	   return null;
           }
            
		}
        catch (Exception e) {
            e.printStackTrace();
        }
		return new int[]{num, rescale, interP};
                                
    }
    /*
     *This method rescales a PlanarImage 
     * @param file
     * @return
     */
    private static PlanarImage rescaleImage(PlanarImage pi, int rescale, int optIntP){
    	if (rescale > 1){
    		ParameterBlock pb = new ParameterBlock();
    		pb.addSource(pi);
    		pb.add(1.0f/rescale);//x scale factor
    		pb.add(1.0f/rescale);//y scale factor
    		pb.add(0.0F);//x translate
    		pb.add(0.0F);//y translate
//    		if (optIntP == 0) pb.add(new InterpolationNearest());
//    		if (optIntP == 1) pb.add(new InterpolationBilinear());
//    		if (optIntP == 2) pb.add(new InterpolationBicubic(10));  //???? 1 oder was????
//    		if (optIntP == 3) pb.add(new InterpolationBicubic2(10));
    		
    		if (optIntP == 0) pb.add(Interpolation.getInstance(Interpolation.INTERP_NEAREST));
    		if (optIntP == 1) pb.add(Interpolation.getInstance(Interpolation.INTERP_BILINEAR));
    		if (optIntP == 2) pb.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
    		if (optIntP == 3) pb.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2));

    		RenderingHints rh = new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));
    		pi = JAI.create("scale", pb, rh);
    	}
    	return pi;
    }
    
	/*
	 * 
	 * @param file
	 * @return
	 */
    private static int[] getSizeOfFirstImg(File file){
   
    	int firstWidth  = 0;
    	int firstHeight = 0;
    	
		try {	          
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            
            if (readers.hasNext()) {//reader(s) available

                // pick the first available ImageReader
                ImageReader reader = readers.next();	    
           
                // attach source to the reader
                reader.setInput(iis, false);  // ImageInputStream,  boolean seekForwardOnly

                // read metadata of first image
                //reader.getNumThumbnails(arg0);
               
            	//BoardJ.appendTexln("ImageHeader: File contains more than one image");
            	firstWidth  = reader.getWidth(0);
            	firstHeight = reader.getHeight(0);
            	//BoardJ.appendTexln("ExtraktSVS: firstWidth" +firstWidth + "  firstHeight " + firstHeight );
  
           }//if
		}
        catch (Exception e) {
            e.printStackTrace();
        }
		return new int[]{firstWidth, firstHeight};
                                
    }


	public static void run() {
		float theRatioW = 0.0f;
   		float theRatioH = 0.0f;
 		boolean allWidthsEqual  = true;
  		boolean allHeightsEqual = true;
	
  		JFileChooser fc = null;
		//JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));// im eclipse system

		try {fc = new JFileChooser();
		}
		catch (Throwable e) {
			System.out.println("ExtractSVS: This plugin requires Java 2 or Swing.");
			return;
		}
	
		fc.setMultiSelectionEnabled(true);
		fc.setDialogTitle("Extract Aperio svs files");
		FileNameExtensionFilter filt     = new FileNameExtensionFilter("svs", "svs");
		fc.addChoosableFileFilter(filt);
	    //fc.addChoosableFileFilter(new FileNameExtensionFilter("svs", "svs"));
	    fc.setFileFilter(filt);        //default setting
		
        currImgDir  = IqmTools.getCurrImgPath();
        //System.out.println("Open: " + defaultDir.toString());
		fc.setCurrentDirectory(currImgDir);
	       
		int returnVal = fc.showOpenDialog(fc);
		if (returnVal!=JFileChooser.APPROVE_OPTION) {
			System.out.println("ExtractSVS: Error: No image(s) extracted");
			return;
		}	
		setDefaultDirectory(fc);
		File[] files = fc.getSelectedFiles();	
		if (files.length==0) { // getSelectedFiles does not work on some JVMs
			files = new File[1];
			files[0] = fc.getSelectedFile();
		}

		int[] selection = displayImageDataAndChoose_ImgNumber_RescaleFactor_InterP(files[0]);
		if (selection == null) return;
		int imageToLoad = selection[0]; //image number
		//System.out.println("ExtractSVS: imageToload: " + imageToLoad);
		int rescale  = selection[1];
		int interP	 = selection[2];
		for (int i = 0; i < files.length; i++){
			SeekableStream s = null;
			PlanarImage    pi = null;
			try {
				s = new FileSeekableStream(files[i].toString());
				TIFFDecodeParam param = new TIFFDecodeParam();
		        ImageDecoder dec = ImageCodec.createImageDecoder("tiff", s, param);
	        	RenderedImage ri = dec.decodeAsRenderedImage(imageToLoad);
	        	pi = new RenderedImageAdapter(ri);
		
			}catch (IOException e) { //try another method e.g for Aperio jpeg 2000 compressed images
				//e.printStackTrace();
				Board.appendTexln("ExtractSVS: Standard method (jpeg compressed,...) failed, trying another method (e.g. for jpeg2000 compression,...)");  	       
	    	    //break;

				BufferedImageReader bR = new BufferedImageReader();
				//BufferedImageReader bR = new BufferedImageReader(new SVSReader());
				
				try {
					bR.setId(files[i].toString());
				} catch (FormatException e2) {
					//e2.printStackTrace();
					Board.appendTexln("ExtractSVS: Could not open the image, perhaps it is defect");
					break;

				} catch (IOException e2) {
					//e2.printStackTrace();
					Board.appendTexln("ExtractSVS: Could not open the image, perhaps it is defect");
					break;
				}
			
				BufferedImage bi = null;
				try {
					//bi = bR.openImage(0, 0, 0, bR.getSizeX(), bR.getSizeY());
					bi = bR.openImage(0);
				} catch (FormatException e1) {
					//e1.printStackTrace();
					Board.appendTexln("ExtractSVS: Could not open the image, perhaps it is defect");
					break;
				} catch (IOException e1) {
					//e.printStackTrace();
					Board.appendTexln("ExtractSVS: Could not open the image, perhaps it is defect");
					break;

				}				
				pi = PlanarImage.wrapRenderedImage(bi);
//				ParameterBlockJAI pb = new ParameterBlockJAI("AWTImage");
//				pb.setParameter("awtImage", bi);
//				pi =(PlanarImage)JAI.create("AWTImage", pb);

			}
        	File newFile = appendTextToImageName(files[i], "_Nr" +String.valueOf(imageToLoad+1)+
        												   "_R"  +String.valueOf(rescale)+
        												   "_Ip" +String.valueOf(interP));
        	
        	pi.setProperty("file_name",  newFile.toString());
        	pi.setProperty("image_name", newFile.getName().toString());	
        	if (rescale > 1){
        		pi = rescaleImage(pi, rescale, interP); //PlanarImgage, rescale factor, interpolation option
        	}
        	
        	//This is necessary because of:
     		//Problem if original image is jpeg2000 33005 compressed and rescaled!
        	//Exception only when saved as jpeg!
        	//ava.lang.IllegalArgumentException: Raster ByteInterleavedRaster is incompatible with ColorModel DirectColorModel;
			//Probably a bug in jpeg codec?
        	ParameterBlock pb = new ParameterBlock();
        	//pb.removeSources();
    	    //pb.removeParameters();
    		pb.addSource(pi);
    		pb.add(DataBuffer.TYPE_BYTE);
    		pi = JAI.create("format", pb);  	  
        	
			if (extension == 0) JAI.create("filestore", pi, newFile.toString(), "TIFF");
			if (extension == 1) JAI.create("filestore", pi, newFile.toString(), "JPEG");
			if (extension == 2) JAI.create("filestore", pi, newFile.toString(), "PNG");
			if (extension == 3) JAI.create("filestore", pi, newFile.toString(), "BMP");
		
			//Print results
 
			int[] size = ExtractSVS.getSizeOfFirstImg(files[i]);
			int firstWidth  = size[0];
			int firstHeight = size[1];
			int width  = pi.getWidth();
			int height = pi.getHeight();
			float ratioWidth  = (float)firstWidth  / width;
    		float ratioHeight = (float)firstHeight / height; 
	
    		//round to 1 decimals
      		ratioWidth  = ratioWidth * 10;
    		ratioHeight = ratioHeight *10; 
      		ratioWidth  = Math.round(ratioWidth);
    		ratioHeight = Math.round(ratioHeight); 
      		ratioWidth  = ratioWidth / 10;
    		ratioHeight = ratioHeight /10; 
    		
     	
    	    if (i == 0){
       			theRatioW = ratioWidth;
       			theRatioH = ratioHeight;
      			       		}
      		if (i != 0){
    			if (theRatioW != ratioWidth)   allWidthsEqual = false;
    			if (theRatioH != ratioHeight) allHeightsEqual = false;  			       			
       		}
    
    		String strNumber       = String.format("%3d", imageToLoad+1);
    		String strWidth        = String.format("%6d", width);
    		String strHeight       = String.format("%6d", height);
    		String strRatioWidth   = String.format("%5.1f", ratioWidth);
    		String strRatioHeight  = String.format("%5.1f", ratioHeight);

			Board.appendTexln("ExtractedSVS: "+ (i+1)+ "/"+files.length);
			Board.appendTexln("Extracted to: "+ newFile);
	  		Board.appendTexln("Extracted image number:" + strNumber + "     Width:" + strWidth + "   Height:" + strHeight+ "     Width Ratio:" + strRatioWidth+":1" + "  Height Ratio:" + strRatioHeight+":1" );


			
		}	
 		Board.appendTexln(" ");
		if (allWidthsEqual){
	 		Board.appendTexln("All width ratios are identical: " +theRatioW );
		}
		else{
	 		Board.appendTexln("All width ratios are NOT identical!!!!" );
		}
		if (allHeightsEqual){
	 		Board.appendTexln("All heigth ratios are identical: " +theRatioH );
		}
		else{
	 		Board.appendTexln("All heigth ratios are NOT identical!!!!" );
		}
 
		//BoardJ.appendTexln(" ");
		
        
	

		
	}

}
